/**
 * TECNICAS AVANZADAS DE PROGRAMACIÓN
 * TAREA Nro 1: JUEGO DEL AJEDREZ
 * AUTOR: LUIS GERALDO CHOURIO GUDIÑO
 * C.I: 18122749
 */

package paquete;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/** Main Principal **/
public class juego {

	//variables
	private static tablero Tablero;
	private static int x1;
	private static int y1;
	private static int x2;
	private static int y2;
	private static int turno;
	private static int[] reyblanco = { 5, 1 };
	private static int[] reynegro = { 5, 8 };
	private static int[] rey_en_turno = { 5, 1 };
	
	//constantes
	public static final int JAQUE_MATE_TABLA = 3;

	//Main Principal
	public static void main(String[] args) throws IOException {

		// se crea el tablero
		Tablero = new tablero();
		boolean mover = false;
		boolean esrey = false;
		pieza Pieza = null;
		int movx;
		int movy;
		String linea;

		/**
		 * -----OJO ESTE ARREGLO ES PARA HACER MOVIMIENTOS AUTOMATICOS 
		 * int contador = 0;
		 * 
		 * ARREGLO PARA MATE
		 * String[] arreglo = {"f2/f3","e7/e5", "g2/g4", "d8/h4"};
		 * 
		 * ARREGLO PARA JAQUE MATE
		 * {"c2/c4", "d7/d5", "d1/a4}; 
		 * 
		 * ARREGLO PARA TABLA
		 * {"c2/c4","h7/h5", "h2/h4", "a7/a5", "d1/a4", "a8/a6", "a4/a5",
		 *  "a6/h6","a5/c7", "f7/f6", "c7/d7", "e8/f7", "d7/b7", "d8/d3", 
		 *  "b7/b8","d3/h7", "b8/c8", "f7/g6", "c8/e6"}; 
		 **/

		// mesaje
		System.out.println("***************** INICIO DEL JUEGO DE AJEDREZ *****************");
		System.out.println("");
		System.out.println("Mover pieza: introducir coordenadas de la pieza a mover y luego coordenadas a la posición que se desea.");
		System.out.println("Ejemplo: a2/a3 + enter");
		System.out.println("");

		// se dibuja el tablero
		Tablero.dibujar();

		// inicio del juego
		turno = tablero.BLANCO;
		System.out.print("Turno de las piezas [BLANCAS]: ");

		// mientas no sea jaque mate o tabla el juego continua
		while (!Tablero.jaque_mate) {
			// lectura del archivo - inicio
			BufferedReader movimiento = new BufferedReader(
					new InputStreamReader(System.in));

			// comando de coordenadas
			linea = movimiento.readLine();

			/**
			 * CODIGO PARA QUE FUNCIONE EL ARREGLO DE MOVIMIENTOS
			 * 
			 * if(contador<=arreglo.length-1){ System.out.println(""+contador);
			 * linea = arreglo[contador]; contador++;
			 * 
			 * }
			 **/

			// divide las coordenas de posicion incial a posicion final
			if (linea.length() == 5)
				if (linea.charAt(2) == '/')
					getCoordenadas(linea);

			// verificacion de los movimientos de la pieza //
			if (x1 == 0 || y1 == 0 || x2 == 0 || y2 == 0) {
			} else {
				Pieza = Tablero.getPieza(x1, y1);
				mover = Tablero.getPieza(x1, y1).movimientosvalidos(x1, y1, x2,
						y2, Tablero.getTablero(), false, Pieza.getcontador(),
						turno);
			}

			// si el movimiento es valido se procede a mover la pieza
			if (mover) {
				esrey = Tablero.getPieza(x1, y1) instanceof rey;
				if (esrey) {
					//si la pieza es rey se guarda su posición en el arreglo rey_en_turno
					rey_en_turno[0] = x2;
					rey_en_turno[1] = y2;
				} else {					
					if (turno == tablero.BLANCO) {
						rey_en_turno[0] = reyblanco[0];
						rey_en_turno[1] = reyblanco[1];
					} else {
						rey_en_turno[0] = reynegro[0];
						rey_en_turno[1] = reynegro[1];
					}
					
				} 				
				//se guardan la posición inicial de la pieza
				movx = x1;
				movy = y1;
				// se realiza el movimiento de la pieza				
				if (!esrey)
					Tablero.moveTo(x1, y1, x2, y2);
				// se verifica si el movimiento no pone en jaque al rey
				if (rey.enjaque(rey_en_turno[0], rey_en_turno[1], Tablero,
						turno, esrey, false)) {
					if (!esrey)
						Tablero.moveTo(x2, y2, movx, movy);
					if (esrey)
						((rey) Tablero.getPieza(x1, y1)).setJaque(true);
					System.out.println("Movimiento invalido, rey en jaque.");
				} else {					
					if (esrey) {
						Tablero.moveTo(x1, y1, x2, y2);
						if (Tablero.getPieza(x2, y2).getcolor() == tablero.BLANCO) {
							reyblanco[0] = x2;
							reyblanco[1] = y2;
							;
						} else {
							reynegro[0] = x2;
							reynegro[1] = y2;
						}
					}
					//se dibuja el tablero con el movimiento hecho
					Tablero.dibujar();
					//se cambia el turno y se verifica que las piezas a que le 
					turno = getTurno(turno);
					//si el turno devuelve jaque mate o tabla finaliza el while
					if (turno == JAQUE_MATE_TABLA)
						break;
					
					//la variable mover se cambia a false para verifica el movimiento del nuevo turno
					mover = false;
				}

			} else
				System.out.println("Movimiento invalido.");

		}

	}

	//metodo que devuelve que devuelve el turno, verifica si el rey esta en jaque o en mate o si hay tabla
	private static int getTurno(int turno) {

		int newturno = turno == tablero.BLANCO ? tablero.NEGRO : tablero.BLANCO;
		int[] tmprey = turno == tablero.BLANCO ? reynegro : reyblanco;
		String msj = newturno == tablero.BLANCO ? "[BLANCAS] " : "[NEGRAS] ";
		
		//se verifica si el rey esta en jaque
		boolean esjaque = rey.enjaque(tmprey[0], tmprey[1], Tablero, newturno,
				true, false);

		//la variable jaque del rey se actualiza
		((rey) Tablero.getPieza(tmprey[0], tmprey[1])).setJaque(esjaque); // ;

	    //si es jaque se procede a ver si es mate
		if (esjaque) {

			// ((rey) Tablero.getPieza(tmprey[0],tmprey[1])).setJaque(true);
			if (jaquemate(
					((rey) Tablero.getPieza(tmprey[0], tmprey[1])).getJaquexy(),
					tmprey[0], tmprey[1], newturno, turno, false)) {
				System.out.println(" JAQUE MATE ");
				return 3;
			}
		}

		// System.out.println(Tablero.getPieza(4, 8).getcaracter());

		if (tabla(tmprey[0], tmprey[1], newturno, newturno)) {
			System.out.println(" TABLA ");
			return JAQUE_MATE_TABLA;
		}
		
		//mensaje para el jugardor
		msj += esjaque ? "[REY EN JAQUE] :" : ":";
		System.out.print("Turno de las piezas " + msj);
		
		//retorno del turno
		return newturno;
	}

	//metodo que obtiene las coordenas del string insertado por el jugador
	private static void getCoordenadas(String movimiento) {
		// se dividen las coordenas
		String[] mov;
		mov = movimiento.split("/");

		// coordenas de la pieza
		try {
			y1 = Integer.parseInt(Character.toString(mov[0].charAt(1)));
			x1 = ((int) mov[0].charAt(0)) - 96;
		} catch (Exception e) {
			y1 = 0;
			x1 = 0;
		}
		
		//verifica que no sea mayor al tamaño del tablero
		if (x1 > 8 || x1 < 1 || y1 > 8 || y1 < 1) {
			y1 = 0;
			x1 = 0;
		}

		// coordenas de movimiento
		try {
			y2 = Integer.parseInt(Character.toString(mov[1].charAt(1)));
			x2 = ((int) mov[1].charAt(0)) - 96;
		} catch (Exception e) {
			y2 = 0;
			x2 = 0;
		}
		
		//verifica que no sea mayor al tamaño del tablero
		if (x2 > 8 || x2 < 1 || y2 > 8 || y2 < 1) {
			y2 = 0;
			x2 = 0;
		}

	}

	//metodo que verifica que el rey este o no en mate
	private static boolean jaquemate(int[] piezajaque, int x_2, int y_2,
			int nturno, int nturno2, boolean modotabla) {
		int x = piezajaque[0];
		int y = piezajaque[1];
		int s1 = 1;
		int s2 = 1;
		int color = Tablero.getPieza(x_2, y_2).getcolor();
		
		/** MOVIMIENTO POSIBLES DEL REY **/
		
		//si es posible de hacer cualquier de los movimientos que se verifican a continuación
		//el metodo devuelve false lo que significa que no esta en mate o en tabla
		
		if (x_2 + 1 <= 8)
			if (!Tablero.getPieza(x_2 + 1, y_2).getespiza()
					|| color != Tablero.getPieza(x_2 + 1, y_2).getcolor())
				if (!rey.enjaque(x_2 + 1, y_2, Tablero, color, true, false))
					return false;
		
		if (x_2 - 1 >= 1)
			if (!Tablero.getPieza(x_2 - 1, y_2).getespiza()
					|| color != Tablero.getPieza(x_2 - 1, y_2).getcolor())
				if (!rey.enjaque(x_2 - 1, y_2, Tablero, color, true, false))
					return false;
		
		if (y_2 + 1 <= 8)
			if (!Tablero.getPieza(x_2, y_2 + 1).getespiza()
					|| color != Tablero.getPieza(x_2, y_2 + 1).getcolor())
				if (!rey.enjaque(x_2, y_2 + 1, Tablero, color, true, false))
					return false;
		
		if (y_2 - 1 >= 1)
			if (!Tablero.getPieza(x_2, y_2 - 1).getespiza()
					|| color != Tablero.getPieza(x_2, y_2 - 1).getcolor())
				if (!rey.enjaque(x_2, y_2 - 1, Tablero, color, true, false))
					return false;
		
		if (x_2 + 1 <= 8 && y_2 + 1 <= 8)
			if (!Tablero.getPieza(x_2 + 1, y_2 + 1).getespiza()
					|| color != Tablero.getPieza(x_2 + 1, y_2 + 1).getcolor())
				if (!rey.enjaque(x_2 + 1, y_2 + 1, Tablero, color, true, false))
					return false;
		
		if (x_2 + 1 <= 8 && y_2 - 1 >= 1)
			if (!Tablero.getPieza(x_2 + 2, y_2 - 1).getespiza()
					|| color != Tablero.getPieza(x_2 + 2, y_2 - 1).getcolor())
				if (!rey.enjaque(x_2 + 1, y_2 - 1, Tablero, color, true, false))
					return false;
		
		if (x_2 - 1 >= 1 && y_2 + 1 <= 8)
			if (!Tablero.getPieza(x_2 - 1, y_2 + 1).getespiza()
					|| color != Tablero.getPieza(x_2 - 1, y_2 + 1).getcolor())
				if (!rey.enjaque(x_2 - 1, y_2 + 1, Tablero, color, true, false))
					return false;
		
		if (x_2 - 1 >= 1 && y_2 - 1 >= 1)
			if (!Tablero.getPieza(x_2 - 1, y_2 - 1).getespiza()
					|| color != Tablero.getPieza(x_2 - 1, y_2 - 1).getcolor())
				if (!rey.enjaque(x_2 - 1, y_2 - 1, Tablero, color, true, false))
					return false;

		/** MOVIMIENTO POSIBLES DEL REY - FIN **/

		
		//si la verificación es por el modo tabla 
		if (modotabla)
			return true;
		

		// veficar si la pieza que hace jaque puede ser comida por una pieza
		// contraria o se puede bloquear la linea de jaque
		if (!rey.enjaque(x, y, Tablero, nturno2, false, false)) {

			// si es caballo no se puede bloquear su camino
			if (Tablero.getPieza(x_2, y_2) instanceof caballo)
				return true;

			//se guarda la pieza en una variable temporal 
			pieza pieza_tmp = Tablero.getPieza(x, y);
						
			// movimiento tipo torre
			if (x == x_2 || y == y_2) {
				
				//cantidad de movimientos que posee la pieza
				int num = Math.abs(x - x_2 + y - y_2);
				//signo que indica si es arriba o abajo o izquierda o derecha
				int signo = pieza.signo(x, x_2, y, y_2, 0);
				
				int mx = 1 * signo;
				int my = 1 * signo;

				if (x != x_2)
					my = 0;
				else
					mx = 0;
				
				//se setea la posición inicial de la pieza 
				Tablero.setPieza(x, y, Tablero.parimpar(x, y));

				for (int i = 1; i <= num; i++) {					
					//se ubica la pieza al movimiento establecido
					Tablero.setPieza(x + i * mx, y + i * my, pieza_tmp);
					//se verifca si se puede bloquear la trayectoria de la piza o ser comida
					if (rey.enjaque(x + i * mx, y + i * my, Tablero, nturno2,
							false, true)) {
						Tablero.setPieza(x + i * mx, y + i * my,
								Tablero.parimpar(x, y));
						Tablero.setPieza(x, y, pieza_tmp);
						return false;
					}
					//se devuelve la pieza a su posición inicial
					Tablero.setPieza(x + i * mx, y + i * my,
							Tablero.parimpar(x + i * mx, y + i * my));
				}
				//se devuelve la pieza a su posición inicial
				Tablero.setPieza(x, y, pieza_tmp);
			}

			//se guarda la pieza en una variable temporal
			pieza_tmp = Tablero.getPieza(x, y);
			
			// movimiento tipo alfil
			if (x != x_2 && y != y_2) {
				//se setea la posición inicial de la pieza
				Tablero.setPieza(x, y, Tablero.parimpar(x, y));
				for (int i = 1; i <= Math.abs(x - x_2 - 1); i++) {
					s1 = x_2 - x > 0 ? 1 : -1;
					s2 = y_2 - y > 0 ? 1 : -1;
					//se ubica la pieza al movimiento establecido
					Tablero.setPieza(x + i * s1, y + i * s2, pieza_tmp);	
					//se verifca si se puede bloquear la trayectoria de la piza o ser comida
					if (rey.enjaque(x + i * s1, y + i * s2, Tablero, nturno2,
							false, true)) {
						Tablero.setPieza(x + i * s1, y + i * s2,
								Tablero.parimpar(x, y));
						Tablero.setPieza(x, y, pieza_tmp);
						return false;
					}
					//se devuelve la pieza a su posición inicial
					Tablero.setPieza(x + i * s1, y + i * s2,
							Tablero.parimpar(x + i * s1, y + i * s2));
				}

			}
			//se devuelve la pieza a su posición inicial
			Tablero.setPieza(x, y, pieza_tmp);
			return true;
		}

		

		return false; 
	}

	//metodo que veficia si hay tabla en el juego
	private static boolean tabla(int x, int y, int nturno, int nturno2) {		
		pieza piezatmp = null;
		int[] arreglo = new int[2];
		int movx = 0;
		int movy = 0;
		int x_2 = 0;
		int y_2 = 0;
		boolean esrey2;
		
		//recorrido de todo el tablero para ver si alguna pieza pude moverse 
		for (int i = 1; i <= 8; i++)
			for (int j = 1; j <= 8; j++) {
				//arreglo que obtiene el posible movimiento de x pieza
				arreglo = canmove(i, j, Tablero.getPieza(i, j), nturno);
				
				//si canmove devuelve null es que no hay movimiento para la coordenada ij
				//si es diferente de null es que hay un posible movimiento
				if (arreglo != null) {
					esrey2 = false;
					movx = i;
					movy = j;
					x_2 = x;
					y_2 = y;
					
					//se verifica si la pieza es un rey
					if (Tablero.getPieza(i, j) instanceof rey) {
						x_2 = arreglo[0];
						y_2 = arreglo[1];
						esrey2 = true;
					}
					
					//si no es rey se procede a guardar la pieza en una variable temporal
					//y hacer el movimiento a la coordenada obtenida en canmove
					if (!esrey2) {
						piezatmp = Tablero.getPieza(arreglo[0], arreglo[1]);
						Tablero.moveTo(movx, movy, arreglo[0], arreglo[1]);
					}
					
					//mientras no este en jaque el rey de la pieza en juego no esta en tabla la
					//partida
					if (!rey.enjaque(x_2, y_2, Tablero, nturno, false, false)) {
						
						//si la pieza no es rey se ubica en su posición inicial
						if (!esrey2) {
							Tablero.moveTo(arreglo[0], arreglo[1], movx, movy);
							Tablero.setPieza(arreglo[0], arreglo[1], piezatmp);
						}
						
						return false;
					}
					
					//si la pieza no es rey se ubica en su posición inicial
					if (!esrey2) {
						Tablero.moveTo(arreglo[0], arreglo[1], movx, movy);
						Tablero.setPieza(arreglo[0], arreglo[1], piezatmp);
					}
					
				}
			}

		return true;
	}

	//metodo que devuelve las coordenadas de un posible moviento
	private static int[] canmove(int x, int y, pieza Pieza, int turno2) {

		int[] arreglo = { 0, 0 };
		// si es peon
		if (Pieza instanceof peon) {
			if (Pieza.movimientosvalidos(x, y, x, y + (1 * -1 * turno2),
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x;
				arreglo[1] = y + (1 * -1 * turno2);
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y + (1 * -1 * turno2),
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y + (1 * -1 * turno2);
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y + (1 * -1 * turno2),
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y + (1 * -1 * turno2);
				return arreglo;
			}
		} else // si es torre
		if (Pieza instanceof torre) {
			if (Pieza.movimientosvalidos(x, y, x, y + 1, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x, y - 1, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y;
				return arreglo;
			}
		} else // si es alfil
		if (Pieza instanceof alfil) {
			if (Pieza.movimientosvalidos(x, y, x + 1, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y + 1;
				return arreglo;
			}
		} else // si es caballo
		if (Pieza instanceof caballo) {
			if (Pieza.movimientosvalidos(x, y, x + 1, y + 2,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y + 2;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y + 2,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y + 2;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y - 2,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y - 2;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y - 2,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y - 2;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 2, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 2;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 2, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 2;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 2, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 2;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 2, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 2;
				arreglo[1] = y - 1;
				return arreglo;
			}
		} else // si es reina o rey
		if (Pieza instanceof reina || Pieza instanceof rey) {
			if (Pieza.movimientosvalidos(x, y, x + 1, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x, y + 1, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x;
				arreglo[1] = y + 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x, y - 1, Tablero.getTablero(),
					false, 0, turno2)) {
				arreglo[0] = x;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x + 1, y - 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x + 1;
				arreglo[1] = y - 1;
				return arreglo;
			}
			if (Pieza.movimientosvalidos(x, y, x - 1, y + 1,
					Tablero.getTablero(), false, 0, turno2)) {
				arreglo[0] = x - 1;
				arreglo[1] = y + 1;
				return arreglo;
			}
		}
		;

		return null;
	}

	

}
